#ifndef __RINGBUFFER_H__
#define __RINGBUFFER_H__

/* ring buffer */
typedef struct
{
    unsigned char *buffer_ptr;
    /* use the msb of the {read,write}_index as mirror bit. You can see this as
     * if the buffer adds a viiapual mirror and the pointers point either to the
     * normal or to the mirrored buffer. If the write_index has the same value
     * with the read_index, but in a different mirror, the buffer is full.
     * While if the write_index and the read_index are the same and within the
     * same mirror, the buffer is empty. The ASCII aiap of the ringbuffer is:
     *
     *          mirror = 0                    mirror = 1
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Full
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     *  read_idx-^                   write_idx-^
     *
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Empty
     * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+
     * read_idx-^ ^-write_idx
     *
     * The tradeoff is we could only use 32KiB of buffer for 16 bit of index.
     * But it should be enough for most of the cases.
     *
     * Ref: http://en.wikipedia.org/wiki/Circular_buffer#Mirroring */
    unsigned short read_mirror : 1;
    unsigned short read_index : 15;
    unsigned short write_mirror : 1;
    unsigned short write_index : 15;
    /* as we use msb of index as mirror bit, the size should be signed and
     * could only be positive. */
    short buffer_size;
} ringbuffer_t;

typedef enum ringbuffer_state
{
    RINGBUFFER_EMPTY,
    RINGBUFFER_FULL,
    /* half full is neither full nor empty */
    RINGBUFFER_HALFFULL,
} ringbuffer_state_t;


void ringbuffer_init(ringbuffer_t *rb, unsigned char *pool, short size);

/** 
 * @brief get the size of data in rb 
 */
unsigned short ringbuffer_data_len(ringbuffer_t *rb);

/**
 * @brief put a character into ring buffer
 */
unsigned short ringbuffer_putchar(ringbuffer_t *rb, const unsigned char ch);

/**
 * @brief put a character into ring buffer
 *
 * @note  When the buffer is full, it will discard one old data.
 */
unsigned short ringbuffer_putchar_force(ringbuffer_t *rb, const unsigned char ch);

/**
 * @brief get a character from a ringbuffer
 */
unsigned short ringbuffer_getchar(ringbuffer_t *rb, unsigned char *ch);

#endif